"""
URL视图处理
"""
import http
from typing import List, Optional, Any
from pydantic import Field
from datetime import timedelta

from tortoise.transactions import atomic
from fastapi import APIRouter, Depends, status, HTTPException, Request, Body, Path
from fastapi.security.oauth2 import OAuth2PasswordRequestForm

# from fastapi_pagination import Page, add_pagination, paginate, LimitOffsetPage
# from casbin_tortoise_adapter.model import CasbinRule

from . import crud, schema, model
from core import settings
from utils.response_code import ResultResponse, HttpStatus
from utils import logger
from utils.utils import verify_password
from auth.auth import create_access_token
from auth.auth_casbin import Authority
from utils import crud as curd
from apps.user.common import getTreeData
from utils.utils import get_password_hash
from apps.auth import model as auth_model
from auth.auth_casbin import get_casbin
from .common import add_role_perm

router = APIRouter()


@router.post("/logout",
             summary="退出登录",
             response_model=ResultResponse[str]
             )
async def logout(request: Request):
    # if settings.REDIS:
    #     # r.hset("Token", "k1", "v1")
    #     r.hdel("Token", request.state.user.pk)
    return ResultResponse(message='退出成功')


@router.post("/login",
             summary="用户登录认证",
             response_model=schema.Token
             )
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    # async def login(form_data: schema.Login):
    """
    通过用户名和密码登录获取 token 值
    :param form_data:
    :return:
    """
    # 验证用户
    user = await crud.get_user_by_name(username=form_data.username)
    if not user:
        logger.info(
            f"用户名认证错误: username:{form_data.username} password:{form_data.password}"
        )
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
                            detail='username or password error')

    # 验证密码
    if not verify_password(form_data.password, user.password):
        logger.info(
            f"用户密码错误: username:{form_data.username} password:{form_data.password}"
        )
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
                            detail='username or password error')

    # 登录成功后返回token
    access_token_expires = timedelta(
        minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(subject=user.username,
                                       expires_delta=access_token_expires)

    # return ResultResponse[schema.Token](result={
    #     'access_token': access_token,
    #     'token_type': 'bearer'
    # })
    return {'access_token': access_token, 'token_type': 'bearer'}


@router.post("/login2",
             summary="Json用户登录认证",
             response_model=ResultResponse[schema.Token]
             )
async def login2(form_data: schema.Login):
    """
    通过用户名和密码登录获取 token 值, json登录
    :param form_data:
    :return:
    """
    # 验证用户
    user = await crud.get_user_by_name(username=form_data.username)
    if not user:
        logger.info(
            f"用户名认证错误: username:{form_data.username} password:{form_data.password}"
        )
        # raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
        #                     detail='username or password error')
        return ResultResponse[schema.Token](message='用户名或密码错误', code=status.HTTP_400_BAD_REQUEST)

    # 验证密码
    if not verify_password(form_data.password, user.password):
        logger.info(
            f"用户密码错误: username:{form_data.username} password:{form_data.password}"
        )
        return ResultResponse[schema.Token](code=status.HTTP_400_BAD_REQUEST, message='用户名或密码错误')

    # 登录成功后返回token
    access_token_expires = timedelta(
        minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(subject=user.username,
                                       expires_delta=access_token_expires)

    # if settings.REDIS:
    #     r.set(user.pk, access_token, ex=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60)

    return ResultResponse[schema.Token](message='登录成功', result={
        'access_token': access_token,
        'token_type': 'bearer'
    })


@router.post('/register',
             summary='用户注册',
             description='注册新用户',
             response_model=ResultResponse[schema.UserOut])
async def register(user: schema.UserCreate):
    user = await crud.create_user(user)
    return ResultResponse[schema.UserOut](result=user)


@router.post('/add',
             summary='后台增加用户',
             description='后台增加用户',
             response_model=ResultResponse[schema.UserOut])
async def user_add(data: schema.UserCreate):
    has_obj = await model.User.filter(username=data.username)
    if has_obj:
        return ResultResponse[str](code=HttpStatus.HTTP_601_ROLE_EXIST, message='用户已存在')
    user = await crud.create_user(data)
    user = await model.User.get(pk=user.id).select_related('role')
    return ResultResponse[schema.UserOut](result=user)


@router.put('/update/{id}',
            summary='更新用户信息',
            name='更新用户信息',
            response_model=ResultResponse[schema.UserOut],
            dependencies=[Depends(Authority('user,update'))])
async def user_update(id: int, request: Request, data: schema.UserCreate):
    has_obj = await model.User.filter(username=data.username).exclude(pk=id)
    if has_obj:
        return ResultResponse[str](code=HttpStatus.HTTP_601_ROLE_EXIST, message='用户已存在')
    obj = await model.User.get(pk=id).select_related('role')
    await model.User.update_from_dict(obj, data.dict()).save()
    return ResultResponse[schema.UserOut](result=obj)


@router.post('/password',
             summary='修改密码',
             description='修改密码',
             response_model=ResultResponse)
async def changePasswrod(pw: schema.ChangePassword, request: Request):
    if pw.passwordOld == pw.passwordNew:
        return ResultResponse(message='新旧密码不能相同!', code=201)
    if pw.passwordNew != pw.confirmPassword:
        return ResultResponse(message='两次输入的密码不相同，请重新输入！', code=201)
    user = request.state.user
    if not verify_password(pw.passwordOld, user.password):
        return ResultResponse(message='旧秘密输入错误', code=201)
    user.password = get_password_hash(pw.passwordNew)
    await user.save()
    return ResultResponse[schema.UserOut](message='修改密码成功')


@router.get("/info",
            summary="获取当前用户信息",
            name="获取当前用户信息",
            response_model=ResultResponse[schema.UserOut])
async def get_user_info(request: Request):
    user = await model.User.filter(id=request.state.user.id).first().prefetch_related('role')
    return ResultResponse[schema.UserOut](result=user)


@router.get('/list',
            summary='获取用户列表',
            description='获取用户列表',
            response_model=ResultResponse[List[schema.UserOut]])
async def get_user_list(page: int = 1, pageSize: int = 20, nickname: Optional[str] = None,
                        username: Optional[str] = None, deptId: Optional[int] = None):
    query = model.User.all()
    if nickname is not None:
        query = query.filter(nickname__icontains=nickname)
    if username is not None:
        query = query.filter(username__icontains=username)
    if deptId is not None:
        query = query.filter(dept_id=deptId)
    query = await query.offset(page - 1).limit(pageSize).prefetch_related('role')
    # user_list = await crud.get_user_list()
    return ResultResponse[List[schema.UserOut]](result=query)


@router.post('/userExist',
             summary='验证用户是否存在',
             description='验证用户是否存在',
             response_model=ResultResponse)
async def user_exist(user: schema.UserExist):
    obj = await crud.get_user_by_name(user.username)
    if obj:
        return ResultResponse(code=601, message='该用户已存在')
    return ResultResponse(code=200, message='ok')


@router.get('/role/list',
            summary='获取角色列表',
            name='获取角色列表',
            response_model=ResultResponse[List[model.RoleOut]],
            dependencies=[Depends(Authority('role,read'))])
async def role_get_list(name: Optional[str] = None, status: Optional[bool] = None):
    query = model.Role.all()
    if name is not None:
        query = query.filter(name__icontains=name)
    if status is not None:
        query = query.filter(status=status)
    query = await query
    return ResultResponse[List[model.RoleOut]](result=query)


@router.post('/role/add',
             summary='添加角色',
             name='添加角色',
             response_model=ResultResponse[model.RoleOut],
             dependencies=[Depends(Authority('role,add'))])
async def add_role(role: model.RoleCreate):
    if await crud.has_role(role.name, role.value):
        return ResultResponse[str](code=HttpStatus.HTTP_601_ROLE_EXIST, message='角色已存在')

    role = await crud.create_role(role)
    return ResultResponse[model.RoleOut](result=role)


#
# @router.delete('/role/del',
#              summary='删除角色',
#              name='删除角色',
#              response_model=ResultResponse[str],
#              dependencies=[Depends(Authority('role,del'))])
# async def del_role(request: Request, role_name: str):
#     result = await crud.delete_role_by_name(role_name)
#     if not result:
#         return ResultResponse[str](code=HttpStatus.HTTP_600_ROLE_NOT_EXIST, message='角色不存在')
#
#     return ResultResponse[str](message='角色已删除')


@router.post('/dept/add',
             summary='添加部门',
             name='添加部门',
             response_model=ResultResponse[model.DeptOut],
             dependencies=[Depends(Authority('dept,add'))])
async def add_dept(dept: model.DeptCreate, request: Request):
    if await crud.has_dept(dept.name):
        return ResultResponse[str](code=HttpStatus.HTTP_601_ROLE_EXIST, message='部门已存在')
    obj = await crud.create_dept(dept)
    return ResultResponse[model.DeptOut](result=obj)


@router.put('/dept/update/{id}',
            summary='更新部门',
            name='更新部门',
            response_model=ResultResponse[model.DeptOut],
            dependencies=[Depends(Authority('dept,update'))])
async def update_dept(id: int, dept: model.DeptCreate, request: Request):
    has_dept = await model.Dept.filter(name=dept.name).exclude(pk=id)
    if has_dept:
        return ResultResponse[str](code=HttpStatus.HTTP_601_ROLE_EXIST, message='部门已存在')
    obj = await model.Dept.get(pk=id)
    await model.Dept.update_from_dict(obj, dept.dict()).save()
    return ResultResponse[model.DeptOut](result=obj)


@router.delete('/dept/del',
               summary='删除部门',
               name='删除部门',
               response_model=ResultResponse[str],
               dependencies=[Depends(Authority('dept,del'))])
async def del_dept(request: Request, ids: List[int]):
    result = await curd.delete_obj_by_ids(model.Dept, ids)
    if not result:
        return ResultResponse[str](code=HttpStatus.HTTP_600_ROLE_NOT_EXIST, message='部门不存在')
    return ResultResponse[str](message='部门已删除')


@router.get('/dept/list', summary='获取部门列表',
            name='获取部门列表',
            # response_model=ResultResponse[str],
            dependencies=[Depends(Authority('dept,read'))])
async def getDeptList(request: Request):
    query = await model.Dept.all()
    keys = ['id', 'name', 'orderNo', 'remark', 'status', 'parent_id', 'created_at']
    res = await getTreeData(query, keys)
    return ResultResponse(result=res)


@router.get('/getPermCode',
            summary='获取权限代码',
            name='获取权限代码',
            response_model=ResultResponse[List[str]])
async def getPermCode(request: Request):
    obj = await model.Role.all().exclude(is_delete=1).values_list('value', flat=True)
    return ResultResponse[List[str]](result=obj)


@router.delete('/role/del',
               summary='删除角色',
               name='删除角色',
               response_model=ResultResponse[str],
               dependencies=[Depends(Authority('role,del'))])
async def del_dept(request: Request, ids: List[int]):
    result = await curd.delete_obj_by_ids(model.Role, ids)
    if not result:
        return ResultResponse[str](code=HttpStatus.HTTP_600_ROLE_NOT_EXIST, message='角色不存在')
    return ResultResponse[str](message='角色已删除')


# @router.post('/role/add',
#              summary='添加角色',
#              name='添加角色',
#              response_model=ResultResponse[model.RoleOut],
#              dependencies=[Depends(Authority('role,add'))])
# async def add_dept(data: model.RoleCreate, request: Request):
#     if await curd.has_obj_by_name(model.Role, data.name):
#         return ResultResponse[str](code=HttpStatus.HTTP_601_ROLE_EXIST, message='角色已存在')
#     obj = await curd.create_obj(model.Role, data)
#     return ResultResponse[model.RoleOut](result=obj)


@router.put('/role/update/{id}',
            summary='更新角色',
            name='更新角色',
            response_model=ResultResponse[model.RoleOut],
            dependencies=[Depends(Authority('role,update'))])
async def update_role(id: int, data: model.RoleCreate):
    has_obj = await model.Role.filter(name=data.value).exclude(pk=id)
    if has_obj:
        return ResultResponse[str](code=HttpStatus.HTTP_601_ROLE_EXIST, message='角色已存在')
    obj = await model.Role.get(pk=id)
    await model.Role.update_from_dict(obj, data.dict()).save()
    return ResultResponse[model.RoleOut](result=obj)


@router.post('/role/setRoleStatus', name='更新角色',
             response_model=ResultResponse[str],
             dependencies=[Depends(Authority('role,update'))])
async def setRoleStatus(data: schema.RoleStatus):
    obj = await model.Role.get(pk=data.id)
    if obj:
        obj.status = data.status
        await obj.save()
        return ResultResponse(message='更新状态成功')
    else:
        return ResultResponse(message='更新状态失败', code=600)


@atomic
@router.put('/role/permission/update/{id}', name='更新角色权限', response_model=ResultResponse,
            dependencies=[Depends(Authority('rolePermission,update'))])
async def role_permission(id: int, data: schema.PermIds):
    role = await model.Role.get_or_none(pk=id)
    if role is None:
        return ResultResponse(message='角色不存在', code=422)
    e = await get_casbin()
    e.enforce.delete_role(role.value)
    for item in data.permission:
        obj = await auth_model.Permission.get(pk=item)
        # if obj is None:
        #     return ResultResponse(message=f'Id为{item}的权限不存在', code=422)
        await add_role_perm(role=role.value, model=obj.model, act=obj.act)
    role.permission = data.permission
    await role.save()
    await e.enforce.load_policy()
    return ResultResponse(message='更新权限成功', code=200)


@router.get('/getAccountInfo',
            summary='获取基本信息',
            description='获取基本信息',
            response_model=ResultResponse[schema.UserAccountInfo])
async def getAccountInfo(request: Request):
    if request.state.user:
        return ResultResponse[schema.UserAccountInfo](result=request.state.user)
    return ResultResponse(code=HttpStatus.HTTP_600_ROLE_NOT_EXIST, message='获取信息错误')


@router.put('/getAccountInfo',
            summary='获取基本信息',
            description='获取基本信息',
            response_model=ResultResponse[schema.UserAccountInfo])
async def updateAccountInfo(request: Request, data: schema.UserAccountInfo):
    obj = request.state.user
    if obj:
        obj = await obj.update_from_dict(data.dict()).save()
        return ResultResponse[schema.UserAccountInfo](result=obj)
    return ResultResponse(code=HttpStatus.HTTP_600_ROLE_NOT_EXIST, message='获取信息错误')
